/*
 * ChatClient.cpp
 *
 *  Created on: 23.10.2011
 *      Author: niea
 */

#include <iostream>

#include "ChatClient.h"
#include "Datagramm.h"
#include "UDPPinger.h"
#include "constants.h"

ChatClient::ChatClient() :
	m_version("1.0"), m_thread_stop_req(false), m_thread(0), m_connected(false) {
}

ChatClient::~ChatClient() {
	disconnect();
}

void ChatClient::setName(std::string const& name) {
	m_name = name;
}

void ChatClient::setPort(size_t port) {
	m_port = port;
}

void ChatClient::assignSocket(ISocket *tcp_socket) {
	m_tcp_socket = tcp_socket;
}

void ChatClient::pingServers() {
	UDPPinger pinger;
	pinger.ping(CONST_PORT);
}

void ChatClient::sendMessage(std::string message) {
	if (!m_connected) {
		std::cout << "Not connected to server" << std::endl;
		return;
	}
	Datagramm datagramm;
	datagramm.getStrings().push_back("SEND");
	datagramm.getStrings().push_back(message);
	m_tcp_socket->sendMessage(datagramm.getDatagramm());
}

void ChatClient::disconnect() {
	if (m_connected) {
		stopThread();
		m_connected = false;

		Datagramm datagramm;
		datagramm.getStrings().push_back("BYE");
		m_tcp_socket->sendMessage(datagramm.getDatagramm());

		m_tcp_socket->disconnect();
		std::cout << "Disconnected" << std::endl;
	}
}

void ChatClient::connect(std::string ip) {
	if (m_tcp_socket->connectServer(ip, m_port) == C_ERROR) {
		std::cerr << "Can not connect to server " << std::endl;
		return;
	}

	Datagramm datagramm;
	datagramm.getStrings().push_back("HELLO");
	datagramm.getStrings().push_back(m_name);
	datagramm.getStrings().push_back(m_version);
	m_tcp_socket->sendMessage(datagramm.getDatagramm());

	std::vector<char> raw_message;
	if (m_tcp_socket->receiveMessage(raw_message) == C_OK) {
		datagramm.putDatagramm(raw_message);
		if (datagramm.getStrings()[0][0] == 'y') {
			m_connected = true;
			m_server_timestamp = datagramm.getStrings()[1];
			startThread();
			std::cout << "Connected to server " << ip << std::endl;
		} else {
			std::cout << "Server refused connection " << std::endl;
		}
	} else {
		std::cerr << "Server did not reply " << std::endl;
	}
}

void ChatClient::listClients() {
	if (!m_connected) {
		std::cout << "Not connected to server" << std::endl;
		return;
	}

	Datagramm datagramm;
	datagramm.getStrings().push_back("LIST");
	m_tcp_socket->sendMessage(datagramm.getDatagramm());

	std::vector<char> raw_message;
	if (m_tcp_socket->receiveMessage(raw_message) == C_OK) {
		datagramm.putDatagramm(raw_message);
		std::cout << "Chat users:" << std::endl;
		datagramm.printStrings();
	} else {
		std::cerr << "Server did not reply " << std::endl;
	}
}

void ChatClient::showHistory() {
	if (!m_connected) {
		std::cout << "Not connected to server" << std::endl;
		return;
	}

	Datagramm datagramm;
	datagramm.getStrings().push_back("HISTORY");
	m_tcp_socket->sendMessage(datagramm.getDatagramm());

	std::vector<char> raw_message;
	if (m_tcp_socket->receiveMessage(raw_message) == C_OK) {

		datagramm.putDatagramm(raw_message);
		datagramm.printStrings(2);
	} else {
		std::cerr << "Server did not reply " << std::endl;
	}
}

int ChatClient::startThread() {
	m_thread_stop_req = false;
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	pthread_create(&m_thread, &attr, threadProcStarter, (void*) this);
}

void ChatClient::stopThread() {
	m_thread_stop_req = true;
	if (m_thread) {
		pthread_join(m_thread, NULL);
	}
}

void* ChatClient::threadProcStarter(void* obj) {
	static_cast<ChatClient*> (obj)->threadProc();
	return NULL;
}

void ChatClient::threadProc() {
	while (!m_thread_stop_req) {
		usleep(CONST_CHECK_PERIOD * 1000);

		Datagramm datagramm;
		datagramm.getStrings().push_back("GET");
		datagramm.getStrings().push_back(m_server_timestamp);
		m_tcp_socket->sendMessage(datagramm.getDatagramm());

		std::vector<char> raw_message;
		if (m_tcp_socket->receiveMessage(raw_message) == C_OK) {

			datagramm.putDatagramm(raw_message);
			m_server_timestamp = datagramm.getStrings()[0];
			if (datagramm.getStrings().size() > 2) {
				std::cout << std::endl;
				datagramm.printStrings(2, ">");
			}
		}
	}
}

